<!--
 * @Date: 2024-12-18 13:55:15
 * @Author: LiSong
 * @LastEditors: LiSong
 * @LastEditTime: 2024-12-18 13:55:17
 * @Description: 通用的上传面板
-->
<template>
  <el-upload drag
    ref="uploadRef"
    :limit="1"
    :auto-upload="false"
    :name="name"
    :on-preview='handlePreview'
    :disabled="disabled"
    :on-remove="handleRemove"
    :on-exceed="handleEceed"
    :show-file-list="showUploadList"
    :on-change="handleChange">
    <el-icon class="el-icon--upload"><upload-filled /></el-icon>
    <div>
      <p>将文件拖动到此处或点击选择文件</p>
      <p>
        支持{{ accept }}格式的单个文件上传导入
      </p>
    </div>
  </el-upload>
</template>

<script setup>
import { reactive, ref } from "vue"
import { ElMessage } from 'element-plus'
import { defAxios as request } from '@/utils/http'
import { UploadFilled } from '@element-plus/icons-vue'
import { genFileId } from 'element-plus'

const emit = defineEmits(['onError', 'onSuccess', 'change', , 'preview', 'download'])
const props = defineProps({
  // 发到后台的文件参数名
  name: { type: String, default: 'file' },
  // 文件类型
  accept: { type: [String, Object] },
  // 上传url
  action: { type: [String] },
  // 上传超时时长：单位为分钟，默认为 5分钟
  timeout: { type: Number, default: 5 },
  // 上传文件大小上限：单位为KB
  maxLimit: { type: Number, default: 20480 },
  // 上传文件大小下限：单位为KB
  minLimit: { type: Number, default: 1 },
  // 是否禁用
  disabled: { type: Boolean, default: false },
  // 上传失败提示语
  failedText: { type: String, default: '上传失败！' },
  // 上传成功提示语
  successText: { type: String, default: '上传成功！' },
  // 是否展示 uploadList
  showUploadList: { type: Boolean, default: true },
})
let fileList = ref([])
let uploadRef = ref('')
/** 上传文件之前的钩子 */
const handleEceed = (files) => {
  const file = files[0]
  const { accept, minLimit, maxLimit, } = props
  const { size, name, } = file
  // 截取文件后缀
  const suffix = name.substring(name.lastIndexOf('.'), name.length)
  if (accept && !accept.includes(suffix)) {
    ElMessage({
      message: `文件类型错误，请选择文件${accept}`,
      type: 'error',
    })
    return false
  }
  if (minLimit && size < (minLimit * 1024)) {
    ElMessage({
      message: `文件大小超过最小限制为${minLimit}KB，请重新选择文件!`,
      type: 'error',
    })
    return false
  }
  if (maxLimit && size > (maxLimit * 1024)) {
    ElMessage({
      message: `文件大小超过最大限制${maxLimit}KB，请重新选择文件!`,
      type: 'error',
    })
    return
  }
  uploadRef.value.clearFiles()
  file.uid = genFileId()
  uploadRef.value.handleStart(file)
  fileList.value.push(file)
}
/** 手动清除方法 */
const handleClear = () => {
  uploadRef.value.clearFiles()
  fileList.value = []
}
/** 手动上传方式 */
const handleUpload = () => {
  if (fileList.value && fileList.value.length > 0) {
    let list = fileList.value
    customRequest({ file: fileList.value[0], list })
  } else {
    ElMessage({
      message: '请选择文件！',
      type: 'warning',
    })
  }
}
/** 点击移除文件时的回调 */
const handleRemove = (file) => {
  const index = fileList.value.indexOf(file)
  const newFileList = fileList.value.slice()
  newFileList.splice(index, 1)
  fileList.value = [...newFileList]
}
/** 自定义上传方法 */
const customRequest = (info) => {
  const { file } = info
  handleRequest({ file })
}
/** 上传的请求方法 */
const handleRequest = (uploadData) => {
  const { action, timeout, failedText, successText, } = props
  if (!action) return false
  request({
    url: action,
    method: 'post',
    data: uploadData,
    timeout: 1000 * 1000 * timeout,
    headers: { 'content-type': 'multipart/form-data' }
  }).then(res => {
    const { code, data, msg } = res
    if (code === 200) {
      ElMessage({
        message: successText,
        type: 'success',
      })
      handleOnSuccess(data)
    } else {
      ElMessage({
        message: msg,
        type: 'error',
      })
      handleOnError(data)
    }
  })
}
/** 上传失败 */
const handleOnError = (data) => {
  handleClear()
  emit('onError', data)
}
/** 上传成功触发 */
const handleOnSuccess = (data) => {
  handleClear()
  emit('onSuccess', data)
}
/** 上传文件改变时的状态 */
const handleChange = (options) => {
  const file = options
  const { accept, minLimit, maxLimit, } = props
  const { size, name, } = file
  // 截取文件后缀
  const suffix = name.substring(name.lastIndexOf('.'), name.length)
  if (accept && !accept.includes(suffix)) {
    ElMessage({
      message: `文件类型错误，请选择文件${accept}`,
      type: 'error',
    })
    return
  }
  if (minLimit && size < (minLimit * 1024)) {
    ElMessage({
      message: `文件大小超过最小限制为${minLimit}KB，请重新选择文件!`,
      type: 'error',
    })
    return
  }
  if (maxLimit && size > (maxLimit * 1024)) {
    ElMessage({
      message: `文件大小超过最大限制${maxLimit}KB，请重新选择文件!`,
      type: 'error',
    })
    return
  }
  fileList.value.push(file.raw)
}
/** 点击文件链接或预览图标时的回调 */
const handlePreview = (file) => {
  emit('preview', file)
}
/** 点击下载文件时的回调 */
const handleDownloa = (file) => {
  emit('download', file)
}
// 对外暴露方法
defineExpose({
  handleUpload,
  handleClear,
  handleOnError,
  handleOnSuccess
})

</script>
